package com.dobbinsoft.iotechn.apigw.ws;

import com.alibaba.fastjson.JSONObject;
import com.dobbinsoft.iotechn.apigw.enums.WebsocketMessageType;
import com.dobbinsoft.iotechn.apigw.ws.handler.WebsocketHandler;
import com.dobbinsoft.iotechn.apigw.ws.message.DeviceSelectWsMessage;
import com.dobbinsoft.iotechn.core.model.UserSession;
import com.dobbinsoft.iotechn.user.api.biz.UserBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;

/**
 * Description: 每一个连接都会创建这个类的实例
 * User: rize
 * Date: 2020/6/27
 * Time: 14:02
 */

@Component
@ServerEndpoint("/data/{access}")
public class DataPointWebsocket implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(DataPointWebsocket.class);

    private static ApplicationContext applicationContext;

    private static Map<String, DataPointWebsocket> sessionMap;

    private static Map<Integer, WebsocketHandler> wsHandlerMap;

    /**
     * 当前访问用户的AccessToken
     */
    private String currentAccessToken;

    /**
     * 当前访问用户Session
     */
    private Session session;

    /**
     * 当设备选中时，将设备Id或AccessKeyId保存在此变量了
     * 当未有设备选中，或非选中该设备时，设备数据点变化，Socket也不推送数据
     */
    private Long currentDevice;

    @OnOpen
    public void open(Session session) throws IOException {
        String access = session.getPathParameters().get("access");
        UserBizService userBizService = applicationContext.getBean(UserBizService.class);
        UserSession userSession = userBizService.getUserSessionByAccessToken(access);
        if (userSession == null) {
            logger.warn("[数据WS] 未授权用户连接WebSocket");
            session.close();
        } else {
            logger.info("[数据WS] 用户连接用户ID:" + userSession.getId());
            this.currentAccessToken = access;
            this.session = session;
            sessionMap.put(access, this);
        }
    }

    @OnMessage
    public void message(String msg, Session session) {
        logger.info("[收到客户端消息] msg=" + msg);
        JSONObject jsonObject = JSONObject.parseObject(msg);
        Integer code = jsonObject.getInteger("code");
        if (code == null) {
            return;
        }
        WebsocketHandler websocketHandler = wsHandlerMap.get(code);
        if (websocketHandler != null) {
            websocketHandler.handle(this, jsonObject.toJavaObject(websocketHandler.getMessageType()));
        }
    }

    @OnClose
    public void close(Session session) {
        logger.info("[数据WS] 失去连接");
        sessionMap.remove(this.currentAccessToken);
    }

    public void sendMessage(String message) {
        try {
            logger.info("[数据WS] 发送 message=" + message);
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            logger.error("[数据WS] IO异常 连接用户ACCESS_TOKEN=" + this.currentAccessToken);
            try {
                this.session.close();
            } catch (IOException ex) {
            }
        }
    }

    public void setCurrentDevice(Long currentDevice) {
        this.currentDevice = currentDevice;
    }

    public Long getCurrentDevice() {
        return currentDevice;
    }

    public Session getSession() {
        return session;
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
        sessionMap = (Map<String, DataPointWebsocket>) applicationContext.getBean("dataWsSessionMap");
        wsHandlerMap = (Map<Integer, WebsocketHandler>) applicationContext.getBean("wsHandlerMap");
    }
}

